﻿using Itech_Run.Application.Shared;
using Itech_Run.Sys.Application.Contracts.Dto;
using Itech_Run.Sys.Application.Contracts.Service;
using Itech_Run.Sys.Domain.Entity;
using System.Linq.Expressions;
using System.Linq.Dynamic.Core;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Domain.Repositories;
using Itech_Run.Sys.Domain.Manager;
using Itech_Run.Application.Contracts.Shared.Dto;

namespace Itech_Run.Sys.Application.Service
{
    public class SysModuleService : BaseApplicationService<Sys_Module>, ISysModuleService
    {
        private readonly IRepository<Sys_Module, string> _sysModuleRepository;
        private readonly IRepository<Sys_RoleModule, string> _sysRoleModuleRepository;
        private readonly IRepository<Sys_UserRole, string> _sysUserRoleRepository;
        private readonly Sys_ModuleManager _sysModuleManager;
        private readonly IRepository<Sys_RoleModuleButton, string> _sysRoleModuleButtonRepository;
        private readonly IRepository<Sys_Role, string> _sysRoleRepository;
        private readonly IRepository<Sys_ModuleButton, string> _sysModuleButtonRepository;
        private readonly IRepository<Sys_Button, string> _sysButtonRepository;

        public SysModuleService(IRepository<Sys_Module, string> sysModuleRepository, IRepository<Sys_RoleModule, string> sysRoleModuleRepository, IRepository<Sys_UserRole, string> sysUserRoleRepository, Sys_ModuleManager sysModuleManager, IRepository<Sys_RoleModuleButton, string> sysRoleModuleButton
            , IRepository<Sys_Role, string> sysRoleRepository, IRepository<Sys_ModuleButton, string> sysModuleButtonRepository, IRepository<Sys_Button, string> sysButtonRepository)
        {
            _sysModuleRepository = sysModuleRepository;
            _sysRoleModuleRepository = sysRoleModuleRepository;
            _sysUserRoleRepository = sysUserRoleRepository;
            _sysModuleManager = sysModuleManager;
            _sysRoleModuleButtonRepository = sysRoleModuleButton;
            _sysRoleRepository = sysRoleRepository;
            _sysModuleButtonRepository = sysModuleButtonRepository;
            _sysButtonRepository = sysButtonRepository;
        }
        public async Task<List<string?>> GetSysModuleApiController()
        {
            return (await _sysModuleRepository.GetQueryableAsync()).Where(t => !string.IsNullOrEmpty(t.ApiController) && t.IsActive == true).Select(t => t.ApiController).Distinct().ToList();
        }
        public async Task<List<string?>> GetSysModuleApiControllerByUserRole(string userId)
        {
            var query = from n in (await _sysModuleRepository.GetQueryableAsync())
                        join m in (await _sysRoleModuleRepository.GetQueryableAsync()) on n.Id equals m.ModuleId
                        join l in (await _sysUserRoleRepository.GetQueryableAsync()) on m.RoleId equals l.RoleId
                        where l.UserId == userId && !string.IsNullOrEmpty(n.ApiController) && n.IsActive == true
                        select n.ApiController;
            return query.Distinct().ToList();
        }
        public async Task<string?> GetAssemblyName(string? apiController)
        {
            var query = (await _sysModuleRepository.GetListAsync(p => p.ApiController == apiController)).Select(s => s.AssemblyName);
            return query.FirstOrDefault();
        }

        public async Task<SysModuleDto> GetAsync(string id)
        {
            var entity = await _sysModuleRepository.GetAsync(id, includeDetails: true);
            return ObjectMapper.Map<Sys_Module, SysModuleDto>(entity);
        }

        public async Task<PagedResultDto<SysModuleDto>> GetListAsync(SysModuleListDto listDto)
        {
            if (string.IsNullOrEmpty(listDto.Sorting)) listDto.Sorting = "Sort asc,Name asc";
            Expression<Func<Sys_Module, bool>> curExpression = s => true;
            if (!string.IsNullOrEmpty(listDto.Name))
                curExpression = curExpression.And(s => s.Name.Contains(listDto.Name));
            if (!string.IsNullOrEmpty(listDto.ParentId))
                curExpression = curExpression.And(s => s.ParentId == listDto.ParentId);
            if (!string.IsNullOrEmpty(listDto.ApplicationCode))
                curExpression = curExpression.And(s => s.ApplicationCode == listDto.ApplicationCode);
            if (listDto.IsActive != null)
                curExpression = curExpression.And(s => s.IsActive == listDto.IsActive);

            var query = (await _sysModuleRepository.WithDetailsAsync()).WhereIf(true, curExpression).OrderBy(listDto.Sorting);
            var items = ObjectMapper.Map<List<Sys_Module>, List<SysModuleDto>>(query.PageBy(listDto.SkipCount, listDto.MaxResultCount).ToList());

            return new PagedResultDto<SysModuleDto>(query.Count(), items);
        }

        public async Task<SysModuleDto> InsertAsync(SysModuleCreateDto dto, string operateUser)
        {
            var sysModule = ObjectMapper.Map<SysModuleCreateDto, Sys_Module>(dto);
            await _sysModuleManager.Check_UniqueAsync(sysModule);
            SetInsertBy(sysModule, operateUser);
            if (dto.ButtonList.Count > 0)
                sysModule.AllocateModuleButton(dto.ButtonList);
            var result = await _sysModuleRepository.InsertAsync(sysModule);
            return ObjectMapper.Map<Sys_Module, SysModuleDto>(result);
        }

        public async Task<SysModuleDto> UpdateAsync(SysModuleUpdateDto dto, string operateUser)
        {
            var sysModule = await _sysModuleRepository.GetAsync(dto.Id, includeDetails: true);
            ObjectMapper.Map(dto, sysModule);
            await _sysModuleManager.Check_UniqueAsync(sysModule);
            SetUpdateBy(sysModule, operateUser);
            sysModule.AllocateModuleButton(dto.ButtonList);
            var result = await _sysModuleRepository.UpdateAsync(sysModule);
            return ObjectMapper.Map<Sys_Module, SysModuleDto>(result);
        }

        public async Task DeleteAsync(string id)
        {
            try
            {
                var sysModule = await _sysModuleRepository.GetAsync(id, includeDetails: true);
                await _sysModuleRepository.DeleteAsync(sysModule);
            }
            catch { }
        }

        public async Task<List<SysModuleTreeDto>> GetSysModuleTree(string application)
        {
            var result = (await _sysModuleRepository.GetListAsync(p => p.ApplicationCode == application && p.IsActive == true, includeDetails: true)).OrderBy(e => e.Sort).ToList();
            return ObjectMapper.Map<List<Sys_Module>, List<SysModuleTreeDto>>(result.Where(s => s.Level == 1).ToList());
        }

        public async Task<List<SysModulePermissionTreeDto>> GetSysModulePermissionTree(string role, string application)
        {
            var result = (await _sysModuleRepository.GetListAsync(p => p.ApplicationCode == application && p.IsActive == true, includeDetails: true)).OrderBy(e => e.Sort).ToList();
            var tree = ObjectMapper.Map<List<Sys_Module>, List<SysModulePermissionTreeDto>>(result.Where(s => s.Level == 1).ToList());
            var userModuleButtons = await getRoleModuleButton(role);
            var modules = await getRoleModules(role);
            //当前角色选中的模块（最多只考虑3级）
            tree.ForEach(item1 =>
            {
                if (modules.Contains(item1.Id))
                {
                    item1.IsChecked = true;
                }
                item1.Children.ForEach(item2 =>
                {
                    if (modules.Contains(item2.Id))
                    {
                        item2.IsChecked = true;
                    }
                    item2.Children.ForEach(item3 =>
                    {
                        if (modules.Contains(item3.Id))
                        {
                            item3.IsChecked = true;
                        }
                    });
                });
            });

            //当前角色选中的模块按钮（最多只考虑3级）
            tree.ForEach(item1 =>
            {
                item1.ButtonList.ForEach(btnItem1 =>
                {
                    if (userModuleButtons.Any(p => p.Param1 == item1.Id && p.Param2 == btnItem1.Id))
                    {
                        btnItem1.IsAuth = true;
                    }
                });
                item1.Children.ForEach(item2 =>
                {
                    item2.ButtonList.ForEach(btnItem2 =>
                    {
                        if (userModuleButtons.Any(p => p.Param1 == item2.Id && p.Param2 == btnItem2.Id))
                        {
                            btnItem2.IsAuth = true;
                        }
                    });
                    item2.Children.ForEach(item3 =>
                    {
                        item3.ButtonList.ForEach(btnItem3 =>
                        {
                            if (userModuleButtons.Any(p => p.Param1 == item3.Id && p.Param2 == btnItem3.Id))
                            {
                                btnItem3.IsAuth = true;
                            }
                        });
                    });
                });
            });
            return tree;
        }

        /// <summary>
        /// 角色有权限访问的模块下的Button
        /// </summary>
        /// <param name="roleName"></param>
        /// <returns></returns>
        private async Task<List<MultiParamDto>> getRoleModuleButton(string roleName)
        {
            var query = from rmb in (await _sysRoleModuleButtonRepository.GetQueryableAsync())
                        where rmb.Role.Name == roleName && rmb.HasAuth == true
                        select new MultiParamDto
                        {
                            Param1 = rmb.ModuleId,
                            Param2 = rmb.ButtonId
                        };

            return query.Distinct().ToList();
        }

        private async Task<List<string>> getRoleModules(string roleName)
        {
            return (await _sysRoleModuleRepository.GetListAsync(p => p.Role.Name == roleName)).Select(s => s.ModuleId).ToList();
        }

        public async Task<List<SysModuleApiPathDto>> GetSysModuleApiPath(string operateUser)
        {
            var query = from m in (await _sysModuleRepository.GetQueryableAsync())
                        join rm in (await _sysRoleModuleRepository.GetQueryableAsync())
                        on m.Id equals rm.ModuleId
                        join r in (await _sysRoleRepository.GetQueryableAsync()).Where(p => p.IsActive == true)
                        on rm.RoleId equals r.Id
                        join ur in (await _sysUserRoleRepository.GetQueryableAsync())
                        on r.Id equals ur.RoleId
                        where m.IsActive == true && ur.UserId == operateUser && m.Url != ""
                        select new
                        {
                            Path = m.Url,
                            Level = m.Level,
                            Id = m.Id,
                            ParentId = m.ParentId
                        };
            var modules = query.Distinct().ToList();

            List<SysModuleApiPathDto> result = new List<SysModuleApiPathDto>();
            var level1Modules = modules.Where(p => p.Level == 1).ToList();
            var level2Modules = modules.Where(p => p.Level == 2).ToList();
            level1Modules.ForEach(item =>
            {
                var temp = new SysModuleApiPathDto();
                temp.Path = item.Path;
                level2Modules.ForEach(childItem =>
                {
                    if (childItem.ParentId == item.Id)
                    {
                        temp.ChildPaths.Add(childItem.Path);
                    }
                });
                result.Add(temp);
            });

            return result;
        }

        public async Task<List<SysModuleButtonAuthDto>> GetSysModuleButtonAuth(string operateUser)
        {
            List<SysModuleButtonAuthDto> result = new List<SysModuleButtonAuthDto>();
            var query = from mc in (await _sysModuleRepository.GetQueryableAsync())
                        join m in (await _sysModuleRepository.GetQueryableAsync())
                        on mc.ParentId equals m.Id
                        join mb in (await _sysModuleButtonRepository.GetQueryableAsync())
                        on mc.Id equals mb.ModuleId
                        join b in (await _sysButtonRepository.GetQueryableAsync())
                        on mb.ButtonId equals b.Id
                        join rmb in (await _sysRoleModuleButtonRepository.GetQueryableAsync()).Where(p => p.HasAuth == true)
                        on new { ModuleId = mc.Id, ButtonId = b.Id } equals new { rmb.ModuleId, rmb.ButtonId }
                        join ur in (await _sysUserRoleRepository.GetQueryableAsync())
                        on rmb.RoleId equals ur.RoleId
                        where mc.IsActive == true && m.IsActive == true && mc.Level == 2 && mc.Url != "" && m.Url != "" && ur.UserId == operateUser
                        select new
                        {
                            Path = m.Url + "/" + mc.Url,
                            Code = b.Code
                        };
            var modules = query.Distinct().ToList();
            modules.Select(s => s.Path).Distinct().ToList().ForEach(item =>
            {
                SysModuleButtonAuthDto temp = new SysModuleButtonAuthDto { Path = item };
                modules.Where(p => p.Path == item).ToList().ForEach(childItem =>
                {
                    temp.Buttons.Add(childItem.Code);
                });
                if (temp.Buttons.Any())
                    result.Add(temp);
            });

            return result;
        }
    }
}
